﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using UDS.Entity;

namespace UDS.Components
{
    /// <summary>
    /// Staff 管理类
    /// </summary>
    public class Staff
    {
        private static StaffNameMap s_nameMap = new StaffNameMap();

        #region Revised

        /// <summary>
        /// 获取指定职位的所有员工
        /// </summary>
        /// <param name="positionId">职位ID</param>
        /// <param name="demission">是获取离职员工列表还是在职员工列表</param>
        public static IList<StaffInfo> GetStaffInPosition(int positionId, bool demission)
        {
            if (positionId <= 0)
            {
                throw new ArgumentOutOfRangeException("positionId", "The position id must be greater than zero.");
            }

            var parameters = new[]
            {
                Database.MakeInParam("@Position_id", SqlDbType.Int, 4, positionId),
                Database.MakeInParam("@Dimission", SqlDbType.Bit, 1, demission),
            };

            return GetStaffList("dbo.sproc_GetStaffInPosition_V2", parameters, true);
        }

        /// <summary>
        /// 获取所有员工
        /// </summary>
        /// <param name="demission">"true"表示离职员工，"false"表示在职员工</param>
        public static IList<StaffInfo> GetAllStaff(bool demission)
        {
            var parameters = new[]
            {
                Database.MakeInParam("@Position_id", SqlDbType.Int, 4, -1), // -1 indicates all positions
                Database.MakeInParam("@Dimission", SqlDbType.Bit, 1, demission),
            };

            return GetStaffList("dbo.sproc_GetStaffInPosition_V2", parameters, true);
        }

        /// <summary>
        /// 获取用户基本信息
        /// </summary>
        /// <param name="staffs">用户ID</param>
        public static IList<StaffInfo> GetStaffInfo(IEnumerable<int> staffs)
        {
            var db = new Database();
            string xml = GenerateStaffXML(staffs);
            var parameters = new[]
            {
                Database.MakeInParam("@xml", SqlDbType.Xml, -1, xml)
            };

            return GetStaffList("dbo.sproc_GetStaffInfoEx_V2", parameters);
        }

        /// <summary>
        /// 获取指定Class（项目，组等）中的人员
        /// </summary>
        public static IList<StaffInfo> GetStaffInTeam(int teamID)
        {
            // create data object and params
            var parameters = new[]
            {
                Database.MakeInParam("@ClassID", SqlDbType.Int, 4, teamID),
            };

            return GetStaffList("dbo.sproc_GetMemberInClass_V2", parameters);
        }

        /// <summary>
        /// 返回某部门及下级部门用户信息
        /// </summary>
        public static IList<StaffInfo> GetStaffByPosition(int PositionID)
        {
            var parameters = new[]
            {
                Database.MakeInParam("@PositionID", SqlDbType.Int, 8, PositionID),
            };

            return GetStaffList("dbo.sproc_GetStaffByPosition_V2", parameters, false);
        }

        /// <summary>
        /// 获取用户基本信息
        /// </summary>
        /// <param name="Username">用户代号</param>
        /// <returns>返回真实姓名</returns>
        public static string GetRealNameByUsername(string username)
        {
            return s_nameMap.GetRealName(username, true);
        }

        /// <summary>
        /// Get the real name for the given user.
        /// </summary>
        public static string GetRealNameByUsername(string Username, bool allowCache)
        {
            return s_nameMap.GetRealName(Username, allowCache);
        }

        /// <summary>
        /// Get the real name of the given users (comma/colon seperated list)
        /// </summary>
        public static string GetRealNameForStaffList(string usernameList)
        {
            return GetRealNameForStaffList(usernameList, /* all */ -1);
        }

        /// <summary>
        /// Get the real name of the given users (comma/colon seperated list)
        /// </summary>
        public static string GetRealNameForStaffList(string usernameList, int max)
        {
            if (max < -1)
            {
                throw new ArgumentOutOfRangeException("max", "The value must be greater than or equal to -1.");
            }

            string[] array = Utility.SplitArray(usernameList);
            if (array != null)
            {
                max = (max == -1) ? array.Length : Math.Min(max, array.Length);

                string[] realNameArray = new string[max];
                int count = 0;
                for (int i = 0; i < max; i++)
                {
                    string userName = array[i];
                    string realName = GetRealNameByUsername(userName, true);
                    if (string.IsNullOrEmpty(realName))
                    {
                        // The user may already be deleted.
                        realName = userName;
                    }

                    realNameArray[count++] = realName;
                }

                return string.Join("; ", realNameArray);
            }

            return string.Empty;
        }

        #endregion Revised

        #region Modify Password

        public static bool ModifyPassword(string userName, string oldPassword, string newPassword)
        {
            var mySql = new Database();

            var parameter = new[]
            {
                Database.MakeInParam("@UserName", SqlDbType.NVarChar, 50, userName),
                Database.MakeInParam("@OldPassword", SqlDbType.NVarChar, 255, oldPassword),
                Database.MakeInParam("@NewPassword", SqlDbType.NVarChar, 255, newPassword),
            };
            return mySql.RunProc("dbo.sproc_ModifyPassword", parameter) >= 0;
        }

        #endregion

        #region 登陆验证

        /// <summary>
        /// 登陆验证
        /// </summary>
        /// <param name="userName">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="needUSBKey">Returns a value indicating whether the USB key is required during authentication.</param>
        /// <returns>返回用户ID</returns>
        public int Login(string userName, string password, out bool needUSBKey)
        {
            var data = new Database();
            var parameters = new[]
            {
                Database.MakeInParam("@username", SqlDbType.NVarChar, 25, userName),
                Database.MakeInParam("@password", SqlDbType.NVarChar, 25, password),
                Database.MakeOutParam("@UserID", SqlDbType.Int, 4),
                Database.MakeOutParam("@IsNeedKey", SqlDbType.Bit, 1)
            };
            data.RunProc("dbo.sproc_StaffLogin", parameters);

            needUSBKey = (bool)parameters[3].Value;
            return (int)parameters[2].Value;
        }

        #endregion

        #region 用户退出

        /// <summary>
        /// 用户退出
        /// </summary>
        /// <param name="userName">用户名</param>
        public void Logout(string userName)
        {
            var data = new Database();
            var parameters = new[]
            {
                Database.MakeInParam("@username", SqlDbType.NVarChar, 25, userName)
            };
            data.RunProc("dbo.sproc_StaffLogout", parameters);
        }

        #endregion

        #region 获取用户基本信息

        /// <summary>
        /// 获取用户基本信息
        /// </summary>
        /// <param name="id">用户ID</param>
        public static StaffInfo GetStaffInfo(int id)
        {
            return GetStaffInfo(id, false);
        }

        /// <summary>
        /// 获取用户基本信息
        /// </summary>
        /// <param name="id">用户ID</param>
        /// <param name="throwExceptionIfNotExist">指定当用户不存在时是否抛出异常</param>
        public static StaffInfo GetStaffInfo(int id, bool throwExceptionIfNotExist)
        {
            var parameters = new[]
            {
                Database.MakeInParam("@StaffID", SqlDbType.Int, 4, id),
            };

            using (var data = new Database())
            {
                using (var dr = data.RunDataReader("dbo.sproc_GetStaffInfo_V2", parameters))
                {
                    if (dr.Read())
                    {
                        return StaffInfo.ReadStaffInfo(dr);
                    }
                }
            }

            if (throwExceptionIfNotExist)
            {
                throw new InvalidOperationException(string.Format("The specified user (id = {0}) does not exist.", id));
            }
            return null;
        }

        #endregion

        #region 获取当前职位中的用户信息

        /// <summary>
        /// 得到该成员职位中的所有成员信息（包括同级别的和所有下属成员）
        /// </summary>
        /// <param name="Username">用户名</param>
        public static IList<StaffInfo> GetStaffFromPosition(string Username)
        {
            return GetStaffFromPosition(Username, true, int.MaxValue);
        }

        /// <summary>
        /// 得到该成员职位中的所有成员信息（包括所有下属成员）
        /// </summary>
        /// <param name="Username">用户名</param>
        public static IList<StaffInfo> GetStaffFromPosition(string Username, bool includePeers)
        {
            return GetStaffFromPosition(Username, includePeers, int.MaxValue);
        }

        /// <summary>
        /// 得到该成员职位中的成员信息
        /// </summary>
        /// <param name="Username">用户名</param>
        /// <param name="includePeers">是否包含同级成员</param>
        /// <param name="postiondepth">下级成员的深度(比如"1"代表直属成员)</param>
        public static IList<StaffInfo> GetStaffFromPosition(string Username, bool includePeers, int numLowerLevels)
        {
            var parameters = new[]
            {
                Database.MakeInParam("@StaffName", SqlDbType.NVarChar, 30, Username),
                Database.MakeInParam("@IncludePeers", SqlDbType.Bit, 0, includePeers),
                Database.MakeInParam("@NumLowerLevels", SqlDbType.Int, 0, numLowerLevels),
            };

            return GetStaffList("dbo.sproc_GetStaffFromPosition_V2", parameters, false);
        }

        #endregion

        #region 使人员复职

        /// <summary>
        /// 使人员复职
        /// </summary>
        /// <param name="staffids">人员id集合</param>
        /// <returns>是否成功</returns>
        public bool ReturnPosition(string staffids)
        {
            var db = new Database();
            var parameters = new[]
            {
                Database.MakeInParam("@StaffIDS", SqlDbType.NVarChar, 300, staffids)
            };
            return ((db.RunProc("dbo.sproc_StaffRehab", parameters) == 0) ? true : false);
        }

        #endregion

        #region 人员更新

        /// <summary>
        /// 人员更新
        /// </summary>
        /// <returns>返回是否成功</returns>
        public int UpdateInfo(long StaffID, string RealName, int Sex, string Birthday, string Password, string Email, string Phone, string Mobile, long PositionID, int Caste)
        {
            var db = new Database();

            var parameters = new[]
            {
                Database.MakeInParam("@StaffID", SqlDbType.Int, 4, StaffID),
                Database.MakeInParam("@RealName", SqlDbType.NVarChar, 50, RealName),
                Database.MakeInParam("@Sex", SqlDbType.Bit, 1, Sex),
                Database.MakeInParam("@Birthday", SqlDbType.DateTime, 8, Birthday),
                Database.MakeInParam("@Password", SqlDbType.NVarChar, 255, Password),
                Database.MakeInParam("@Email", SqlDbType.NVarChar, 500, Email),
                Database.MakeInParam("@Phone", SqlDbType.NVarChar, 50, Phone),
                Database.MakeInParam("@Mobile", SqlDbType.NVarChar, 50, Mobile),
                Database.MakeInParam("@PositionID", SqlDbType.Int, 4, PositionID),
                Database.MakeInParam("@Caste", SqlDbType.Int, 4, Caste)
            };
            return db.RunProc("dbo.sproc_UpdateStaffInfo", parameters);
        }

        #endregion

        #region 人员离职

        /// <summary>
        /// 人员离职
        /// </summary>
        /// <param name="staffs">人员ID</param>
        /// <returns>返回是否成功</returns>
        public static bool Dimission(IEnumerable<int> staffs)
        {
            if (staffs == null)
            {
                return true;
            }

            string xml = GenerateStaffXML(staffs);
            var db = new Database();
            var parameters = new[]
            {
                Database.MakeInParam("@xml", SqlDbType.Xml, -1, xml)
            };
            return db.RunProc("dbo.sproc_StaffDimission", parameters) == 0 ? true : false;
        }

        #endregion

        #region 人员复职

        /// <summary>
        /// 人员复职
        /// </summary>
        /// <param name="staffs">人员ID</param>
        /// <returns>返回是否成功</returns>
        public static bool Rehab(IEnumerable<int> staffs)
        {
            if (staffs == null)
            {
                return true;
            }

            string xml = GenerateStaffXML(staffs);
            var db = new Database();
            var parameters = new[]
            {
                Database.MakeInParam("@xml", SqlDbType.Xml, -1, xml)
            };

            return db.RunProc("dbo.sproc_StaffRehab", parameters) == 0 ? true : false;
        }

        #endregion

        #region 得到剩余的在岗人员

        /// <summary>
        /// 得到剩余的在岗人员
        /// </summary>
        /// <param name="staffids">原来人员,分割</param>
        /// <returns></returns>
        public SqlDataReader GetRemainStaff(string staffids)
        {
            var data = new Database();
            var parameters = new[]
            {
                Database.MakeInParam("@staffids", SqlDbType.NVarChar, 300, staffids)
            };

            try
            {
                // run the stored procedure
                return data.RunDataReader("dbo.sproc_GetRemainStaff", parameters);
            }
            catch (Exception ex)
            {
                Logger.Log(ex.ToString());
                return null;
            }
        }

        #endregion

        #region 得到所有在职人员

        [Obsolete("Call Staff.GetAllStaff instead of run sproc_GetAllStaff")]
        public SqlDataReader GetAllStaffs()
        {
            var data = new Database();
            try
            {
                // run the stored procedure
                return data.RunDataReader("dbo.sproc_GetAllStaff");
            }
            catch (Exception ex)
            {
                Logger.Log(ex.ToString());
                throw new Exception("人员信息读取出错!", ex);
            }
        }

        #endregion

        #region 得到所有人员

        public SqlDataReader GetTotalStaffs()
        {
            var data = new Database();
            try
            {
                // run the stored procedure
                return data.RunDataReader("dbo.sproc_GetTotalStaff");
            }
            catch (Exception ex)
            {
                Logger.Log(ex.ToString());
                throw new Exception("人员信息读取出错!", ex);
            }
        }

        #endregion

        #region 根据用户真实姓名得到id

        public SqlDataReader GetStaffIDByRealName(string realname)
        {
            var db = new Database();
            var parameters = new[]
            {
                Database.MakeInParam("@realname", SqlDbType.NVarChar, 100, realname)
            };
            return db.RunDataReader("dbo.sproc_GetStaffIDByRealName", parameters);
        }

        #endregion

        #region 根据roleid得到staff

        public SqlDataReader GetStaffsFromRole(int role)
        {
            var data = new Database();
            try
            {
                // run the stored procedure
                var parameters = new[]
                {
                    Database.MakeInParam("@RoleID", SqlDbType.Int, 4, role)
                };
                return data.RunDataReader("dbo.sproc_GetStaffInRole", parameters);
            }
            catch (Exception ex)
            {
                Logger.Log(ex.ToString());
                throw new Exception("人员信息读取出错!", ex);
            }
        }

        #endregion

        #region 人员查询

        /// <summary>
        /// 人员查询
        /// </summary>
        /// <param name="staffname">用户名或者真实姓名</param>
        /// <param name="positionid">职位id</param>
        /// <param name="mobile">手机号码</param>
        /// <param name="email">email</param>
        /// <param name="gender">性别</param>
        /// <param name="searchbound">Dont't know yet.</param>
        public SqlDataReader Find(string staffname, int positionid, string mobile, string email, string gender, string searchbound)
        {
            // Build a SQL statement for selecting a collection of users based on the specified search criteriacrit.
            var sb = new StringBuilder(256);

            #region SELECT Clause

            if (positionid <= 0)
            {
                sb.Append(
                    @"SELECT
    p.Position_Name,
    s.*,
    CASE s.Sex
        When 1 Then N'男'
        Else N'女'
    End AS SexName
FROM
    dbo.UDS_Staff s
    LEFT OUTER JOIN dbo.UDS_Staff_In_Position sp ON s.Staff_ID = sp.Staff_ID
    INNER JOIN dbo.UDS_Position p ON sp.Position_ID = p.Position_ID
WHERE
    s.Staff_ID > 0");
            }
            else
            {
                sb.Append(
                    @"SELECT
    p.Position_Name,
    s.*,
    CASE s.Sex
        When 1 Then N'男'
        Else N'女'
    End AS SexName
FROM
    dbo.UDS_Staff s
    INNER JOIN dbo.UDS_Staff_In_Position sp ON s.Staff_ID = sp.Staff_ID
    INNER JOIN dbo.UDS_Position p ON sp.Position_ID = p.Position_ID
WHERE
    s.Staff_ID > 0");
            }

            #endregion SELECT Clause

            #region WHERE Clause

            // Username or real name
            staffname = CleanSearchString(staffname);
            if (!string.IsNullOrEmpty(staffname))
            {
                sb.AppendFormat(" AND (s.Staff_Name LIKE N'%{0}%' OR s.RealName LIKE N'%{0}%')", staffname);
            }

            // Mobile number
            mobile = CleanSearchString(mobile);
            if (!string.IsNullOrEmpty(mobile))
            {
                sb.AppendFormat(" AND (s.Mobile LIKE N'%{0}%')", mobile);
            }

            // Email
            email = CleanSearchString(email);
            if (!string.IsNullOrEmpty(email))
            {
                sb.AppendFormat(" AND (s.Email LIKE N'%{0}%')", email);
            }

            // Sex
            if (!string.IsNullOrEmpty(gender))
            {
                if (string.Compare(gender, "male", true) == 0)
                {
                    sb.Append(" AND (s.Sex = 1)");
                }
                else if (string.Compare(gender, "female", true) == 0)
                {
                    sb.Append(" AND (s.Sex = 0)");
                }
            }

            // Position
            if (positionid > 0)
            {
                sb.AppendFormat(" AND (p.Position_ID = {0})", positionid);
            }

            if (string.Compare(searchbound, "on", true) == 0)
            {
                sb.Append(" AND (s.Dimission = 0)");
            }
            else if (string.Compare(searchbound, "off", true) == 0)
            {
                sb.Append(" AND (s.Dimission = 1)");
            }

            #endregion

            var db = new Database();

            // run the stored procedure
            var parameters = new[]
            {
                Database.MakeInParam("@sql", SqlDbType.NVarChar, 2048, sb.ToString()),
            };
            return db.RunDataReader("dbo.sproc_StaffSearch", parameters);
        }

        #endregion

        #region 设置用户是否需要硬件KEY验证

        /// <summary>
        /// 设置用户是否需要硬件KEY验证
        /// </summary>
        /// <param name="staffs">人员ID</param>
        /// <param name="IsNeedKey">是否需要登陆</param>
        /// <returns>返回是否成功</returns>
        public bool SetIsNeedKey(IEnumerable<int> staffs, bool IsNeedKey)
        {
            if (staffs == null)
            {
                return true;
            }

            /*
             * XML format:
             * <staffs>
             *  <s id="" />
             * </staffs>
             */
            WriteElement w = delegate(XmlWriter writer, object obj)
            {
                writer.WriteStartElement("s");
                writer.WriteAttributeString("id", ((int)obj).ToString());
                writer.WriteEndElement();
            };
            string xml = Utility.GenerateXML(staffs, "staffs", w);
            var db = new Database();

            var parameters = new[]
            {
                Database.MakeInParam("@xml", SqlDbType.Xml, -1, xml),
                Database.MakeInParam("@IsNeedKey", SqlDbType.Bit, 1, IsNeedKey)
            };
            return db.RunProc("dbo.sproc_Staff_SetIsNeedKey", parameters) == 0 ? true : false;
        }

        #endregion

        #region Others

        public static string GenerateStaffXML(IEnumerable<int> staffs)
        {
            /*
             * XML format:
             * <staffs>
             *  <s id="" />
             * </staffs>
             */
            WriteElement w = delegate(XmlWriter writer, object obj)
            {
                writer.WriteStartElement("s");
                writer.WriteAttributeString("id", ((int)obj).ToString());
                writer.WriteEndElement();
            };
            return Utility.GenerateXML(staffs, "staffs", w);
        }

        /// <summary>
        /// Get a list of staffs using the specified stored procedure.
        /// </summary>
        internal static IList<StaffInfo> GetStaffList(string procName, IEnumerable<SqlParameter> parameters)
        {
            return GetStaffList(procName, parameters, true);
        }

        /// <summary>
        /// Get a list of staffs using the specified stored procedure.
        /// </summary>
        internal static IList<StaffInfo> GetStaffList(string procName, IEnumerable<SqlParameter> parameters, bool readPositionInfo)
        {
            var list = new List<StaffInfo>();
            using (var db = new Database())
            {
                using (var dr = db.RunDataReader(procName, parameters))
                {
                    while (dr.Read())
                    {
                        list.Add(StaffInfo.ReadStaffInfo(dr, readPositionInfo));
                    }
                }
            }

            return list;
        }

        /// <summary>
        /// Cleans up the specified string for a sql query.
        /// </summary>
        private static string CleanSearchString(string searchString)
        {
            if (string.IsNullOrEmpty(searchString))
            {
                return null;
            }

            // Replaces all the "*" character as "%".
            searchString = searchString.Replace('*', '%');

            if (!string.IsNullOrEmpty(searchString))
            {
                // Removes all the nunword characters except "%".
                searchString = Regex.Replace(searchString, @"[^\w%]+", " ", RegexOptions.Compiled | RegexOptions.Multiline);
            }

            if (!string.IsNullOrEmpty(searchString))
            {
                // Removes all the extra spaces.
                searchString = Regex.Replace(searchString, @" {1,}", " ", RegexOptions.Compiled | RegexOptions.Multiline);
            }

            if (!string.IsNullOrEmpty(searchString))
            {
                return searchString.Trim();
            }
            return searchString;
        }

        #endregion
    }
}